import { $set } from '@feng3d/serialization';
import { EdgesGeometry3D, Node3D, PerspectiveCamera3D, PointLight3D, Scene3D, WebGLRenderer3D, WireframeGeometry3D } from 'feng3d-three';
import '../../extension/controls/VertexNormalsHelper3D';
import { VertexNormalsHelper3D } from '../../extension/controls/VertexNormalsHelper3D';
import '../../extension/controls/VertexTangentsHelper3D';
import { VertexTangentsHelper3D } from '../../extension/controls/VertexTangentsHelper3D';
import { GLTFLoader3D } from '../../extension/loaders/GLTFLoader3D';

const rootPath = '../../';

let scene: Scene3D;
let renderer: WebGLRenderer3D;
let camera: PerspectiveCamera3D;
let light: PointLight3D;
let vnh: VertexNormalsHelper3D;
let vth: VertexTangentsHelper3D;

init();
animate();

function init()
{
    renderer = new Node3D().addComponent('WebGLRenderer3D');
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    //

    camera = new Node3D().addComponent('PerspectiveCamera3D', { fov: 70, aspect: window.innerWidth / window.innerHeight, near: 1, far: 1000 });
    camera.entity.position.z = 400;

    scene = new Node3D().addComponent('Scene3D');

    light = new Node3D().addComponent('PointLight3D');
    light.entity.position.set(200, 100, 150);
    scene.entity.addChild(light.entity);

    scene.entity.addChild(new Node3D().addComponent('PointLightHelper3D', { light, sphereSize: 15 }).entity);

    const gridHelper = new Node3D().addComponent('GridHelper3D', { size: 400, divisions: 40, color1: 0x0000ff, color2: 0x808080 });
    gridHelper.entity.position.y = -150;
    gridHelper.entity.position.x = -150;
    scene.entity.addChild(gridHelper.entity);

    const polarGridHelper = new Node3D().addComponent('PolarGridHelper3D', { radius: 200, radials: 16, circles: 8, divisions: 64, color1: 0x0000ff, color2: 0x808080 });
    polarGridHelper.entity.position.y = -150;
    polarGridHelper.entity.position.x = 200;
    scene.entity.addChild(polarGridHelper.entity);

    const loader = new GLTFLoader3D();
    loader.load(`${rootPath}models/gltf/LeePerrySmith/LeePerrySmith.glb`, function (gltf)
    {
        const mesh = gltf.scene.children[0].getComponent('Mesh3D');

        mesh.geometry.computeTangents(); // generates bad data due to degenerate UVs

        const group = new Node3D();
        group.scale.multiplyScalar(50);
        scene.entity.addChild(group);

        // To make sure that the matrixWorld is up to date for the boxhelpers
        group.updateMatrixWorld(true);

        group.addChild(mesh.entity);

        vnh = new Node3D().addComponent('VertexNormalsHelper3D', { object: mesh, size: 5 });
        scene.entity.addChild(vnh.entity);

        vth = new Node3D().addComponent('VertexTangentsHelper3D', { object: mesh, size: 5 });
        scene.entity.addChild(vth.entity);

        scene.entity.addChild(new Node3D().addComponent('BoxHelper3D', { object: mesh }).entity);

        const wireframe = $set(new WireframeGeometry3D(), { geometry: mesh.geometry });
        let line = new Node3D().addComponent('LineSegments3D', { geometry: wireframe });
        line.material.depthTest = false;
        line.material.opacity = 0.25;
        line.material.transparent = true;
        line.entity.position.x = 4;
        group.addChild(line.entity);

        scene.entity.addChild(new Node3D().addComponent('BoxHelper3D', { object: line }).entity);

        const edges = $set(new EdgesGeometry3D(), { geometry: mesh.geometry });
        line = new Node3D().addComponent('LineSegments3D', { geometry: edges });
        line.material.depthTest = false;
        line.material.opacity = 0.25;
        line.material.transparent = true;
        line.entity.position.x = -4;
        group.addChild(line.entity);
        scene.entity.addChild(new Node3D().addComponent('BoxHelper3D', { object: line }).entity);

        scene.entity.addChild(new Node3D().addComponent('BoxHelper3D', { object: group }).entity);
        scene.entity.addChild(new Node3D().addComponent('BoxHelper3D', { object: scene }).entity);
    });

    //

    window.addEventListener('resize', onWindowResize);
}

function onWindowResize()
{
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate()
{
    requestAnimationFrame(animate);

    const time = -performance.now() * 0.0003;

    camera.entity.position.x = 400 * Math.cos(time);
    camera.entity.position.z = 400 * Math.sin(time);
    camera.entity.lookAt(scene.entity.position);

    light.entity.position.x = Math.sin(time * 1.7) * 300;
    light.entity.position.y = Math.cos(time * 1.5) * 400;
    light.entity.position.z = Math.cos(time * 1.3) * 300;

    if (vnh) vnh.update();
    if (vth) vth.update();

    renderer.render(scene, camera);
}
